home *** CD-ROM | disk | FTP | other *** search
/ Info-Mac 4 / Info_Mac IV CD-ROM (Pacific HiTech Inc.)(August 1994).iso / Development / Source / Macintosh Tracker Source / Tracker Client Folder / Core 18⁄March⁄1994 / Memory.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-03-18  |  23.2 KB  |  942 lines  |  [TEXT/KAHL]

  1. /* Memory.c */
  2.  
  3. #define COMPILING_MEMORY_C
  4. #include "Memory.h"
  5. #include "MiscInfo.h"
  6. #include "Compatibility.h"
  7.  
  8. #define EnableHeapChecking (False)
  9.  
  10. #define MemoryFillPattern (0x81)
  11.  
  12. #if EnableHeapChecking
  13.     #define HEAPCHECK(plop) CheckHeap(plop)
  14. #else
  15.     #define HEAPCHECK(plop)
  16. #endif
  17.  
  18. #if __option(mc68020) /* { */
  19.     #define CodeFor68020
  20. #else /* }{ */
  21.     #define CodeFor68000
  22. #endif /* } */
  23.  
  24. /* these allow us to make sure everything that gets allocated also gets deleted */
  25. EXECUTE(long NumHandlesAllocated = 0;)
  26. EXECUTE(long NumPointersAllocated = 0;)
  27. EXECUTE(long MaxNumHandlesAllocated = 0;)
  28. EXECUTE(long MaximumStackSize = 0;)
  29. EXECUTE(char* TopOfStack;)
  30.  
  31. /* the following macros should be defined in MiscInfo.h */
  32. /* PRIMARYMEMCACHESIZE:  number of bytes in the primary memory cache */
  33. /* SECONDARYMEMCACHESIZE:  number of bytes in the secondary mem cache */
  34. /* GRABTEMPMEM:  if True, then the memory manager grabs any temporary memory */
  35. /*  that might be available if the first allocation fails.  If false, the program */
  36. /*  waits until no memory can be removed from the local heap before using temp mem. */
  37. /* USETEMPMEM:  if True, the program uses temporary memory.  if False, it won't */
  38. /*  even try to allocate temporary memory. */
  39.  
  40. /* number of grow zone functions that can be installed */
  41. #define MaxNumGrowZones (4)
  42.  
  43.  
  44. /* handle preserving stash of emergency memory (NIL = invalid) */
  45. static Handle            MemCache1 = NIL;
  46. static Handle            MemCache2 = NIL;
  47. static MyBoolean    MemCacheRestoreFlag = True;
  48.  
  49. static MyBoolean    GrowZoneInstalled = False;
  50. static MyBoolean    DisableDefaultGrowZone = False;
  51. static GrowZoneFuncPtrType    GrowZoneList[MaxNumGrowZones];
  52. static short            NumGrowZones = 0;
  53. static MyBoolean    GrowZoneInProgress = False;
  54.  
  55. static MyBoolean    AllocCanFail = False;
  56.  
  57. #ifdef MEMDEBUG /* { */
  58.     #define IsANothing (0)
  59.     #define IsAHandle (1)
  60.     #define IsAPointer (2)
  61.     #define NUMTAGCHARS (20)
  62.     typedef struct StoreRec
  63.         {
  64.             void*        HandPtr; /* whatever it is (4 chars) */
  65.             short        Type; /* handle or pointer (2 chars) */
  66.             char        Tag[NUMTAGCHARS]; /* string for taging */
  67.             struct StoreRec**    Next;
  68.         } StoreRec;
  69.     StoreRec**            TrackList;
  70.     static short        MemDumpFile;
  71.     void        RegisterHandle(Handle TheHandle);
  72.     void        DeregisterHandle(Handle TheHandle);
  73.     void        RegisterPointer(Ptr ThePointer);
  74.     void        DeregisterPointer(Ptr ThePointer);
  75.     void        SetUpChecking(void);
  76.     void        ShutOffChecking(void);
  77.     void        MemPrint(char* Str,...);
  78. #else /* }{ */
  79.     #define RegisterHandle(TheHandle)
  80.     #define DeregisterHandle(TheHandle)
  81.     #define RegisterPointer(ThePointer)
  82.     #define DeregisterPointer(ThePointer)
  83.     #define SetUpChecking()
  84.     #define ShutOffChecking()
  85. #endif /* } */
  86.  
  87.  
  88. /* prototypes */
  89. static pascal long        GlobalGrowZone(ulong BytesNeeded);
  90.  
  91.  
  92. /* attempt to allocate handle */
  93. Handle        AllocHandle(ulong Size)
  94.     {
  95.         Handle            Temp;
  96.         OSErr                Err;
  97.  
  98.         HEAPCHECK();
  99.         StackSizeTest();
  100.         ERROR(Size >= 0x00800000,
  101.             PRERR(AllowResume,"Allocating Handle larger than 8 Megabytes."));
  102.         /* this prevents a purge of our zone allowing us to allocate space from temporary */
  103.         /* memory before we use the stash */
  104.         DisableDefaultGrowZone = True; /* prevent grow zone from purging stash. */
  105.         /* if the cache exists, we try to allocate from our heap first.  Otherwise, we */
  106.         /* try to allocate from temporary memory, in order to preserve as much of our */
  107.         /* memory as we can.  Other grow zone functions still work (e.g. CDiskCache purge) */
  108.         #if GRABTEMPMEM && USETEMPMEM /* { */
  109.         if ((MemCache1 == NIL) && HasGoodTemporaryMemory)
  110.             {
  111.                 Temp = TempNewHandle(Size,&Err);
  112.                 ERROR((MemErr != noErr) && (MemErr != memFullErr),
  113.                     PRERR(ForceAbort,"Memory manager error"));
  114.                 if (Temp != NIL) goto GoodHandle;
  115.             }
  116.         #endif /* } */
  117.         Temp = NewHandle(Size);
  118.         ERROR((MemErr != noErr) && (MemErr != memFullErr),
  119.             PRERR(ForceAbort,"Memory manager error"));
  120.         if (Temp != NIL) goto GoodHandle;
  121.         #if USETEMPMEM /* { */
  122.         if (HasGoodTemporaryMemory)
  123.             {
  124.                 Temp = TempNewHandle(Size,&Err);
  125.                 ERROR((MemErr != noErr) && (MemErr != memFullErr),
  126.                     PRERR(ForceAbort,"Memory manager error"));
  127.                 if (Temp != NIL) goto GoodHandle;
  128.             }
  129.         #endif /* } */
  130.         if (MemCache1 != NIL)
  131.             {
  132.                 DisposHandle(MemCache1);
  133.                 ERROR((MemErr != noErr) && (MemErr != memFullErr),
  134.                     PRERR(ForceAbort,"Memory manager error"));
  135.                 MemCache1 = NIL;
  136.                 Temp = NewHandle(Size);
  137.                 ERROR((MemErr != noErr) && (MemErr != memFullErr),
  138.                     PRERR(ForceAbort,"Memory manager error"));
  139.                 if (Temp != NIL) goto GoodHandle;
  140.             }
  141.         if (MemCache2 != NIL)
  142.             {
  143.                 DisposHandle(MemCache2);
  144.                 ERROR((MemErr != noErr) && (MemErr != memFullErr),
  145.                     PRERR(ForceAbort,"Memory manager error"));
  146.                 MemCache2 = NIL;
  147.                 Temp = NewHandle(Size);
  148.                 ERROR((MemErr != noErr) && (MemErr != memFullErr),
  149.                     PRERR(ForceAbort,"Memory manager error"));
  150.                 if (Temp != NIL) goto GoodHandle;
  151.             }
  152.         if ((Temp == NIL) && (!AllocCanFail))
  153.             {
  154.                 PRERR(ForceAbort,"AllocHandle couldn't allocate any memory.");
  155.             }
  156.      GoodHandle:
  157.         DisableDefaultGrowZone = False;  /* reenable stash raiding */
  158.         EXECUTE(if (Temp != NIL) NumHandlesAllocated += 1);
  159.         EXECUTE(if (NumHandlesAllocated > MaxNumHandlesAllocated)
  160.             MaxNumHandlesAllocated = NumHandlesAllocated);
  161.         EXECUTE(if (Temp != NIL) {RegisterHandle(Temp);})
  162.         EXECUTE(if (Temp != NIL) {long Scan; for (Scan = 0; Scan < Size; Scan += 1)
  163.             {(*Temp)[Scan] = MemoryFillPattern;}})
  164.         return Temp;
  165.     }
  166.  
  167.  
  168. Handle        AllocHandleCanFail(ulong Size)
  169.     {
  170.         Handle    Temp;
  171.  
  172.         AllocCanFail = True;
  173.         Temp = AllocHandle(Size);
  174.         AllocCanFail = False;
  175.         return Temp;
  176.     }
  177.  
  178.  
  179. /* attempt to allocate a pointer */
  180. Ptr                AllocPtr(ulong Size)
  181.     {
  182.         Ptr                Temp;
  183.  
  184.         HEAPCHECK();
  185.         StackSizeTest();
  186.         ERROR(Size > 0x00800000,
  187.             PRERR(AllowResume,"Allocating Pointer larger than 8 Megabytes."));
  188.         Temp = NewPtr(Size); /* grow zone function automatically raids MemCache if necessary */
  189.         ERROR((MemErr != noErr) && (MemErr != memFullErr),
  190.             PRERR(ForceAbort,"Memory manager error"));
  191.         if ((Temp == NIL) && (!AllocCanFail))
  192.             {
  193.                 PRERR(ForceAbort,"CMemory::AllocPtr couldn't allocate any memory.");
  194.             }
  195.         EXECUTE(NumPointersAllocated += 1);
  196.         EXECUTE(if (Temp != NIL) {RegisterPointer(Temp);})
  197.         EXECUTE(if (Temp != NIL) {long Scan; for (Scan = 0; Scan < Size; Scan += 1)
  198.             {Temp[Scan] = MemoryFillPattern;}})
  199.         return Temp;
  200.     }
  201.  
  202.  
  203. Ptr                AllocPtrCanFail(ulong Size)
  204.     {
  205.         Ptr        Temp;
  206.  
  207.         AllocCanFail = True;
  208.         Temp = AllocPtr(Size);
  209.         AllocCanFail = False;
  210.         return Temp;
  211.     }
  212.  
  213.  
  214. /* release handle and attempt to restore cache */
  215. void            ReleaseHandle(Handle TheHand)
  216.     {
  217.         StackSizeTest();
  218.         ERROR(TheHand==NIL,PRERR(ForceAbort,"ReleaseHandle tried to dispose a NIL handle."));
  219.         DeregisterHandle(TheHand);
  220.         DisposHandle(TheHand);
  221.         EXECUTE(NumHandlesAllocated -= 1);
  222.         if (((MemCache1 == NIL) || (MemCache2 == NIL)) && (!GrowZoneInProgress)
  223.             && MemCacheRestoreFlag)
  224.             {
  225.                 RestoreMemCache();
  226.             }
  227.         HEAPCHECK();
  228.     }
  229.  
  230.  
  231. /* release pointer and attempt to restore cache */
  232. void            ReleasePtr(Ptr ThePtr)
  233.     {
  234.         StackSizeTest();
  235.         ERROR(ThePtr==NIL,PRERR(ForceAbort,"ReleasePtr tried to dispose a NIL pointer."));
  236.         DeregisterPointer(ThePtr);
  237.         DisposPtr(ThePtr);
  238.         ERROR((MemErr != noErr) && (MemErr != memFullErr),
  239.             PRERR(ForceAbort,"Memory manager error"));
  240.         EXECUTE(NumPointersAllocated -= 1);
  241.         if (((MemCache1 == NIL) || (MemCache2 == NIL)) && (!GrowZoneInProgress)
  242.             && MemCacheRestoreFlag)
  243.             {
  244.                 RestoreMemCache();
  245.             }
  246.         HEAPCHECK();
  247.     }
  248.  
  249.  
  250. #ifdef DEBUG /* { */
  251.  
  252. #pragma parameter __D0 LocalHandleSize(__A0)
  253. pascal long LocalHandleSize(Handle h) = 0xA025;
  254. #pragma parameter __D0 LocalPtrSize(__A0)
  255. pascal long LocalPtrSize(Ptr p) = 0xA021;
  256.  
  257. ulong            HandleSize(Handle h)
  258.     {
  259.         long        Result;
  260.  
  261.         CheckHandleExistence(h);
  262.         if ((Result = LocalHandleSize(h)) < 0)
  263.             {
  264.                 PRERR(AllowResume,"HandleSize returned negative value.");
  265.             }
  266.         ERROR((MemErr != noErr) && (MemErr != memFullErr),
  267.             PRERR(ForceAbort,"Memory manager error"));
  268.         return Result;
  269.     }
  270.  
  271.  
  272. ulong            PtrSize(Ptr p)
  273.     {
  274.         long        Result;
  275.  
  276.         CheckPtrExistence(p);
  277.         if ((Result = LocalPtrSize(p)) < 0)
  278.             {
  279.                 PRERR(AllowResume,"PtrSize returned negative value.");
  280.             }
  281.         ERROR((MemErr != noErr) && (MemErr != memFullErr),
  282.             PRERR(ForceAbort,"Memory manager error"));
  283.         return Result;
  284.     }
  285.  
  286. #endif /* } */
  287.  
  288.  
  289. /* see if the primary cache exists (True == it does) */
  290. MyBoolean    FirstMemCacheValid(void)
  291.     {
  292.         StackSizeTest();
  293.         if ((MemCache1 == NIL) && MemCacheRestoreFlag)
  294.             {
  295.                 RestoreMemCache(); /* try to restore it */
  296.             }
  297.         return (MemCache1 != NIL);
  298.     }
  299.  
  300.  
  301. /* see if the secondary cache exists (True == it does) */
  302. MyBoolean    SecondMemCacheValid(void)
  303.     {
  304.         StackSizeTest();
  305.         if ((MemCache2 == NIL) && MemCacheRestoreFlag)
  306.             {
  307.                 RestoreMemCache(); /* try to restore it */
  308.             }
  309.         return (MemCache2 != NIL);
  310.     }
  311.  
  312.  
  313. /* attempt to restore the emergency cache */
  314. void            RestoreMemCache(void)
  315.     {
  316.         MyBoolean            GrowZoneDisableSaveStat;
  317.  
  318.         StackSizeTest();
  319.         GrowZoneDisableSaveStat = DisableDefaultGrowZone;
  320.         DisableDefaultGrowZone = True;
  321.         if (!GrowZoneInProgress)
  322.             {
  323.                 if (MemCache2 == NIL)
  324.                     {
  325.                         MemCache2 = NewHandle(SECONDARYMEMCACHESIZE);
  326.                         ERROR((MemErr != noErr) && (MemErr != memFullErr),
  327.                             PRERR(ForceAbort,"Memory manager error"));
  328.                     }
  329.                 if ((MemCache2 != NIL) && (MemCache1 == NIL))
  330.                     {
  331.                         MemCache1 = NewHandle(PRIMARYMEMCACHESIZE);
  332.                         ERROR((MemErr != noErr) && (MemErr != memFullErr),
  333.                             PRERR(ForceAbort,"Memory manager error"));
  334.                     }
  335.             }
  336.         DisableDefaultGrowZone = GrowZoneDisableSaveStat;
  337.     }
  338.  
  339.  
  340. /* this lets you set whether or not ReleasePtr and ReleaseHandle should try to */
  341. /* restore the memcaches if they have been used. */
  342. void            SetMemCacheRestore(MyBoolean Flag)
  343.     {
  344.         StackSizeTest();
  345.         MemCacheRestoreFlag = Flag;
  346.     }
  347.  
  348.  
  349. #pragma options(!mc68020) /* this code works no matter what */
  350.  
  351. /* initialize the cache */
  352. void            InitMemory(void)
  353.     {
  354.         static MyBoolean    Done = False;
  355.         long            Count;
  356.         char            SillyVariable;
  357.  
  358.         /* this stuff is removed because it might cause bad things to happen. */
  359. //    SetTopOfStack(&SillyVariable);
  360. //    SetApplLimit(&SillyVariable - STACKSIZE);
  361.         MaxApplZone();
  362.  
  363.         ERROR(Done,PRERR(ForceAbort,"InitMemory called more than once."));
  364.         RestoreMemCache();
  365.         if (!GrowZoneInstalled)
  366.             {
  367.                 SetGrowZone((ProcPtr)&GlobalGrowZone);
  368.                 GrowZoneInstalled = True;
  369.             }
  370.         /* NumMasters should be in the MiscInfo.h file */
  371.         for (Count = NumMasters - 1; Count >= 0; Count -= 1)
  372.             {
  373.                 MoreMasters();
  374.             }
  375.         SetUpChecking();
  376.         Done = True;
  377.     }
  378.  
  379.  
  380. void            FlushMemory(void)
  381.     {
  382.         static MyBoolean    Done = False;
  383.  
  384.         ERROR(Done,PRERR(ForceAbort,"FlushMemory called more than once."));
  385.         ERROR(NumHandlesAllocated!=0,PRERR(AllowResume,
  386.             "Some handles are still allocated just before quitting."));
  387.         ERROR(NumPointersAllocated!=0,PRERR(AllowResume,
  388.             "Some pointers are still allocated just before quitting."));
  389.         ShutOffChecking();
  390.         Done = True;
  391.     }
  392.  
  393. #ifdef CodeFor68020 /* { */
  394.     #pragma options(mc68020) /* turn it back on */
  395. #endif /* } */
  396.  
  397.  
  398. /* install a new grow zone function */
  399. void            InstallGrowZone(GrowZoneFuncPtrType MyGrowZone)
  400.     {
  401.         StackSizeTest();
  402.         ERROR(NumGrowZones >= MaxNumGrowZones,
  403.             PRERR(AllowResume,"Attempt to allocate too many grow zone functions."));
  404.         GrowZoneList[NumGrowZones++] = MyGrowZone;
  405.     }
  406.  
  407. #define SIGVAL1 ('This')
  408. #define SIGVAL2 (' is ')
  409. #define SIGVAL3 ('my s')
  410. #define SIGVAL4 ('ig!!')
  411. EXECUTE(long            Signature1 = SIGVAL1;)
  412. EXECUTE(long            Signature2 = SIGVAL2;)
  413. EXECUTE(long            Signature3 = SIGVAL3;)
  414. EXECUTE(long            Signature4 = SIGVAL4;)
  415.  
  416. /* grow zone that gets invoked */
  417. static pascal long        GlobalGrowZone(ulong BytesNeeded)
  418.     {
  419.         long        AccumulatedFreeSpace;
  420.         short        Scan;
  421.         long        TemporaryA5;
  422.  
  423.         TemporaryA5 = SetCurrentA5();
  424.  
  425.         StackSizeTest();
  426.  
  427.         /* test to see if A5 is set up properly */
  428.         ERROR((SIGVAL1 != Signature1) || (SIGVAL2 != Signature2)
  429.             || (SIGVAL3 != Signature3) || (SIGVAL4 != Signature4),Debugger());
  430.  
  431.         GrowZoneInProgress = True;
  432.         Scan = 0;
  433.         AccumulatedFreeSpace = 0;
  434.         while ((Scan < NumGrowZones) && (AccumulatedFreeSpace < BytesNeeded))
  435.             {
  436.                 ERROR((Scan >= NumGrowZones),PRERR(ForceAbort,
  437.                     "GlobalGrowZone very strange error occurred."));
  438.                 AccumulatedFreeSpace
  439.                     += (*(GrowZoneList[Scan]))(BytesNeeded - AccumulatedFreeSpace);
  440.                 Scan += 1;
  441.             }
  442.         if ((AccumulatedFreeSpace < BytesNeeded) && (!DisableDefaultGrowZone)
  443.             && (MemCache1 != NIL))
  444.             {
  445.                 /* if calling all installed grow zones still couldn't free enough memory */
  446.                 /* and we are allowed to empty the stash, we'll do it */
  447.                 DisposHandle(MemCache1);
  448.                 MemCache1 = NIL;
  449.                 AccumulatedFreeSpace += PRIMARYMEMCACHESIZE;
  450.             }
  451.         if ((AccumulatedFreeSpace < BytesNeeded) && (!DisableDefaultGrowZone)
  452.             && (MemCache2 != NIL))
  453.             {
  454.                 DisposHandle(MemCache2);
  455.                 MemCache2 = NIL;
  456.                 AccumulatedFreeSpace += SECONDARYMEMCACHESIZE;
  457.             }
  458.         GrowZoneInProgress = False;
  459.  
  460.         SetA5(TemporaryA5);
  461.  
  462.         return AccumulatedFreeSpace; /* this is how much we managed to dig up */
  463.     }
  464.  
  465.  
  466.  
  467. #ifdef MEMDEBUG /* { */
  468.  
  469. #pragma options(!mc68020) /* this code works no matter what */
  470.  
  471.  
  472. Handle    DupSysHandle(Handle Original)
  473.     {
  474.         Handle        Temp;
  475.  
  476.         if (Original == NIL)
  477.             {
  478.                 Temp = AllocHandle(0); /* return an empty handle */
  479.                 SetTag(Temp,"DupSysHandle Result");
  480.                 return Temp;
  481.             }
  482.         Temp = AllocHandle(LocalHandleSize(Original));
  483.         SetTag(Temp,"DupSysHandle Result");
  484.         MemCpy(*Temp,*Original,LocalHandleSize(Original));
  485.         return Temp;
  486.     }
  487.  
  488.  
  489. void            RegisterHandle(Handle TheHandle)
  490.     {
  491.         StoreRec**    Temp;
  492.  
  493.         Temp = (StoreRec**)NewHandle(sizeof(StoreRec));
  494.         (**Temp).Next = TrackList;
  495.         TrackList = Temp;
  496.         (**Temp).Type = IsAHandle;
  497.         (**Temp).HandPtr = TheHandle;
  498.         (**Temp).Tag[0] = 0;
  499.     }
  500.  
  501.  
  502. void            DeregisterHandle(Handle TheHandle)
  503.     {
  504.         StoreRec**    Scan;
  505.         StoreRec**    Lag;
  506.         Handle            Temp;
  507.  
  508.         Scan = TrackList;
  509.         Lag = NIL;
  510.         while ((Scan != NIL) && ((**Scan).HandPtr != TheHandle))
  511.             {
  512.                 Lag = Scan;
  513.                 Scan = (**Scan).Next;
  514.             }
  515.         if (Scan == NIL)
  516.             {
  517.                 PRERR(ForceAbort,"Deletion of nonexistent handle.");
  518.             }
  519.         if ((**Scan).Type != IsAHandle)
  520.             {
  521.                 PRERR(ForceAbort,"Deletion of Handle via ReleasePtr.");
  522.             }
  523.         if (Lag == NIL)
  524.             {
  525.                 Temp = (Handle)TrackList;
  526.                 TrackList = (**Scan).Next;
  527.                 DisposHandle(Temp);
  528.             }
  529.          else
  530.             {
  531.                 Temp = (Handle)(**Lag).Next;
  532.                 (**Lag).Next = (**Scan).Next;
  533.                 DisposHandle(Temp);
  534.             }
  535.     }
  536.  
  537.  
  538. void            RegisterPointer(Ptr ThePointer)
  539.     {
  540.         StoreRec**    Temp;
  541.  
  542.         Temp = (StoreRec**)NewHandle(sizeof(StoreRec));
  543.         (**Temp).Next = TrackList;
  544.         TrackList = Temp;
  545.         (**Temp).Type = IsAPointer;
  546.         (**Temp).HandPtr = ThePointer;
  547.         (**Temp).Tag[0] = 0;
  548.     }
  549.  
  550.  
  551. void            DeregisterPointer(Ptr ThePointer)
  552.     {
  553.         StoreRec**    Scan;
  554.         StoreRec**    Lag;
  555.         Handle            Temp;
  556.  
  557.         Scan = TrackList;
  558.         Lag = NIL;
  559.         while ((Scan != NIL) && ((**Scan).HandPtr != ThePointer))
  560.             {
  561.                 Lag = Scan;
  562.                 Scan = (**Scan).Next;
  563.             }
  564.         if (Scan == NIL)
  565.             {
  566.                 PRERR(ForceAbort,"Deletion of nonexistent pointer.");
  567.             }
  568.         if ((**Scan).Type != IsAPointer)
  569.             {
  570.                 PRERR(ForceAbort,"Deletion of Pointer via ReleaseHandle.");
  571.             }
  572.         if (Lag == NIL)
  573.             {
  574.                 Temp = (Handle)TrackList;
  575.                 TrackList = (**Scan).Next;
  576.                 DisposHandle(Temp);
  577.             }
  578.          else
  579.             {
  580.                 Temp = (Handle)(**Lag).Next;
  581.                 (**Lag).Next = (**Scan).Next;
  582.                 DisposHandle(Temp);
  583.             }
  584.     }
  585.  
  586.  
  587. void            SetTag(void* TheRef, char* TheTag)
  588.     {
  589.         StoreRec**    Scan;
  590.         short                TagScan;
  591.  
  592.         Scan = TrackList;
  593.         while ((Scan != NIL) && ((**Scan).HandPtr != TheRef))
  594.             {
  595.                 Scan = (**Scan).Next;
  596.             }
  597.         if (Scan == NIL)
  598.             {
  599.                 PRERR(ForceAbort,"Handle/Ptr couldn't be found by SetTag.");
  600.             }
  601.          else
  602.             {
  603.                 for (TagScan = 0; TagScan < NUMTAGCHARS; TagScan += 1)
  604.                     {
  605.                         (**Scan).Tag[TagScan] = TheTag[TagScan];
  606.                     }
  607.             }
  608.     }
  609.  
  610.  
  611. void        CheckHandleExistence(Handle TheHandle)
  612.     {
  613.         StoreRec**        Scan;
  614.  
  615.         StackSizeTest();
  616.         Scan = TrackList;
  617.         while (Scan != NIL)
  618.             {
  619.                 if (((**Scan).Type == IsAHandle) && ((**Scan).HandPtr == TheHandle))
  620.                     {
  621.                         return;
  622.                     }
  623.                 Scan = (**Scan).Next;
  624.             }
  625.         PRERR(ForceAbort,"Undefined Handle used.");
  626.     }
  627.  
  628.  
  629. void        CheckPtrExistence(Ptr ThePointer)
  630.     {
  631.         StoreRec**        Scan;
  632.  
  633.         StackSizeTest();
  634.         Scan = TrackList;
  635.         while (Scan != NIL)
  636.             {
  637.                 if (((**Scan).Type == IsAPointer) && ((**Scan).HandPtr == ThePointer))
  638.                     {
  639.                         return;
  640.                     }
  641.                 Scan = (**Scan).Next;
  642.             }
  643.         PRERR(ForceAbort,"Undefined Handle used.");
  644.     }
  645.  
  646.  
  647. void            SetUpChecking(void)
  648.     {
  649.         TrackList = NIL;
  650.     }
  651.  
  652. void            ShutOffChecking(void)
  653.     {
  654.         char                DumpName[] = {"\p MemCheck Still Allocated Dump"};
  655.         StoreRec**    Scan;
  656.         char                TagTemp[NUMTAGCHARS+1];
  657.         short                TagScan;
  658.         short                VRefNum;
  659.  
  660.         FSDelete((unsigned char*)DumpName,0);
  661.         ERROR(Create((unsigned char*)DumpName,0,AUDITCREATOR,'TEXT') != noErr,
  662.             PRERR(ForceAbort,"Memory's ShutOffChecking couldn't create dump file."));
  663.         ERROR(FSOpen((unsigned char*)DumpName,0,&MemDumpFile) != noErr,PRERR(ForceAbort,
  664.             "Memory's ShutOffChecking couldn't open dump file for writing."));
  665.         MemPrint("These handles and pointers are still allocated:");
  666.         Scan = TrackList;
  667.         while (Scan != NIL)
  668.             {
  669.                 for (TagScan = NUMTAGCHARS - 1; TagScan >= 0; TagScan -= 1)
  670.                     {
  671.                         TagTemp[TagScan] = (**Scan).Tag[TagScan];
  672.                     }
  673.                 TagTemp[NUMTAGCHARS] = 0;
  674.                 switch ((**Scan).Type)
  675.                     {
  676.                         case IsAHandle:
  677.                             MemPrint("Handle %x '%t'",(**Scan).HandPtr,TagTemp);
  678.                             break;
  679.                         case IsAPointer:
  680.                             MemPrint("Pointer %x '%t'",(**Scan).HandPtr,TagTemp);
  681.                             break;
  682.                     }
  683.                 Scan = (**Scan).Next;
  684.             }
  685.         GetVRefNum(MemDumpFile,&VRefNum);
  686.         FSClose(MemDumpFile);
  687.         FlushVol("\p",VRefNum);
  688.     }
  689.  
  690.  
  691. /* some va_args crud for MemPrint */
  692. typedef void *va_list;
  693. #define __va(arg)                &arg + 1
  694. #define va_start(p, arg)        p = __va(arg)
  695. #define va_arg(p, type)            *(* (type **) &p)++
  696. #define va_end(p)
  697.  
  698. /* I lifted this from Audit.c */
  699. /* this prints a string in the same way that printf does.  it accepts these options: */
  700. /* %x = hexadecimal long */
  701. /* %t = C String (text) */
  702. #define BUFSIZE (256)
  703. void            MemPrint(char* Str,...)
  704.     {
  705.         va_list        pa;
  706.         char            Buffer[BUFSIZE];
  707.         long            BufPtr;
  708.         static char    Hex[16] = {"0123456789abcdef"};
  709.  
  710.         BufPtr = 0;
  711.         va_start(pa,Str);
  712.         while (*Str != 0)
  713.             {
  714.                 if (*Str == '%')
  715.                     {
  716.                         Str += 1;
  717.                         switch (*Str)
  718.                             {
  719.                                 case 'x':
  720.                                     {
  721.                                         char        Buf[9];
  722.                                         short        Count;
  723.                                         long        Num;
  724.  
  725.                                         Num = va_arg(pa,long);
  726.                                         for (Count = 8; Count >= 1; Count -= 1)
  727.                                             {
  728.                                                 Buf[Count] = Hex[Num & 0x0000000f];
  729.                                                 Num = Num >> 4;
  730.                                             }
  731.                                         Buf[0] = '$';
  732.                                         for (Count = 0; Count < 9; Count += 1)
  733.                                             {
  734.                                                 Buffer[BufPtr++] = Buf[Count];
  735.                                                 ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,
  736.                                                     "MemPrint buffer overrun."));
  737.                                             }
  738.                                     }
  739.                                     break;
  740.                                 case 't':
  741.                                     {
  742.                                         char*        Strp;
  743.  
  744.                                         Strp = va_arg(pa,char*);
  745.                                         while (*Strp != 0)
  746.                                             {
  747.                                                 Buffer[BufPtr++] = *(Strp++);
  748.                                             }
  749.                                         ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,"MemPrint buffer overrun."));
  750.                                     }
  751.                                     break;
  752.                             }
  753.                         Str += 1;
  754.                     }
  755.                  else
  756.                     {
  757.                         Buffer[BufPtr++] = *(Str++);
  758.                         ERROR(BufPtr>=BUFSIZE,PRERR(ForceAbort,"MemPrint buffer overrun."));
  759.                     }
  760.             }
  761.         Buffer[BufPtr++] = 0x0d;
  762.         FSWrite(MemDumpFile,&BufPtr,Buffer);
  763.     }
  764.  
  765. #ifdef CodeFor68020 /* { */
  766.     #pragma options(mc68020) /* turn it back on if necessary */
  767. #endif /* } */
  768.  
  769.  
  770. #else /* }{  this next part is "#ifndef MEMDEBUG" */
  771.  
  772.  
  773. #ifdef DEBUG /* { */
  774.  
  775. /* this is the DEBUG (but not MEMDEBUG) version */
  776. void        CheckHandleExistence(Handle TheHandle)
  777.     {
  778.         StackSizeTest();
  779.         /* check for various signs of a bad handle.  note that the last two */
  780.         /* won't work if you have a lot of memory & are running the program way up. */
  781.         if ((((ulong)TheHandle & 0x03) != 0)
  782.             || (TheHandle == NIL)
  783.             || (((ulong)*TheHandle & 0x03) != 0)
  784.             || (*TheHandle == NIL)
  785.             || (((ulong)TheHandle & 0xfc000000) != 0)
  786.             || (((ulong)*TheHandle & 0xfc000000) != 0))
  787.             {
  788.                 PRERR(ForceAbort,"Undefined/Garbage Handle used.");
  789.             }
  790.     }
  791.  
  792.  
  793. void        CheckPtrExistence(Ptr ThePointer)
  794.     {
  795.         StackSizeTest();
  796.         /* check for various signs of a bad pointer.  note that the last two */
  797.         /* won't work if you have a lot of memory & are running the program way up. */
  798.         if ((((ulong)ThePointer & 0x03) != 0)
  799.             || (ThePointer == NIL)
  800.             || (((ulong)ThePointer & 0xfc000000) != 0))
  801.             {
  802.                 PRERR(ForceAbort,"Undefined/Garbage Pointer used.");
  803.             }
  804.     }
  805.  
  806. #endif /* } */
  807.  
  808.  
  809. #endif /* } */
  810.  
  811.  
  812. #ifdef DEBUG /* { */
  813.  
  814. #define MAXITERATION (1024L*1024L)
  815.  
  816. /* this checks the heap.  It is, of course, a complete hack, probably won't */
  817. /* run in 24 bit mode, and will need to be totally redone for any new systems. */
  818. void            CheckHeap(void)
  819.     {
  820.         Zone*            MyZone;
  821.         char*            LowestValidAddress;
  822.         char*            HighestValidAddress;
  823.         char*            BlockScan;
  824.         char*            MasterPointerScan;
  825.         char*            Temp;
  826.         long            CurrentBlockSize;
  827.         long            IterateCount;
  828.         long            StupidUnusedVariable;
  829.  
  830.         StackSizeTest();
  831.         MyZone = ApplicZone();
  832.         LowestValidAddress = (char*)&(MyZone->heapData);
  833.         HighestValidAddress = MyZone->bkLim;
  834.         if (HighestValidAddress > (char*)&StupidUnusedVariable)
  835.             {
  836.                 DebugStr("\pHeap bkLim is invalid");
  837.                 return;
  838.             }
  839.  
  840.         BlockScan = LowestValidAddress;
  841.         IterateCount = 0;
  842.         while (BlockScan != HighestValidAddress)
  843.             {
  844.                 IterateCount += 1;
  845.                 /* with a little work, we have discerned that: */
  846.                 /* first byte of block contains: 0x80 = relocatable, */
  847.                 /* 0x40 = nonrelocatable, 0x00 = free */
  848.                 /* second byte of block contains resource bits */
  849.                 /* fourth byte of block contains size correction */
  850.                 switch ((uchar)BlockScan[0])
  851.                     {
  852.                         case 0x80:
  853.                             Temp = (char*)*(long*)(BlockScan + 8); /* get relative handle */
  854.                             Temp = Temp + (long)MyZone; /* get absolute handle */
  855.                             if ((Temp < LowestValidAddress) || (Temp >= HighestValidAddress))
  856.                                 {
  857.                                     DebugStr("\pRelative handle invalid");
  858.                                     return;
  859.                                 }
  860.                             if ((char*)*(long*)Temp != (BlockScan + 12))
  861.                                 {
  862.                                     DebugStr("\pMaster pointer points to wrong block");
  863.                                     return;
  864.                                 }
  865.                             break;
  866.                         case 0x40:
  867.                             if ((char*)MyZone != (char*)*(long*)(BlockScan + 8))
  868.                                 {
  869.                                     DebugStr("\pNonrelocatable block invalid heap reference");
  870.                                     return;
  871.                                 }
  872.                             break;
  873.                         case 0x00:
  874.                             break;
  875.                         default:
  876.                             DebugStr("\pInvalid block tag");
  877.                             return;
  878.                     }
  879.                 /* now checking that block size works out properly */
  880.                 CurrentBlockSize = *(long*)(BlockScan + 4);
  881.                 BlockScan += CurrentBlockSize;
  882.                 if ((BlockScan < LowestValidAddress)
  883.                     || (BlockScan > HighestValidAddress)
  884.                     || ((CurrentBlockSize & 0x03) != 0)
  885.                     || (CurrentBlockSize < 12))
  886.                     {
  887.                         DebugStr("\pCorrupt Heap");
  888.                         return;
  889.                     }
  890.                 if (IterateCount > MAXITERATION)
  891.                     {
  892.                         DebugStr("\pHeap check iteration limit exceeded");
  893.                         return;
  894.                     }
  895.             }
  896.  
  897.         MasterPointerScan = MyZone->hFstFree;
  898.         IterateCount = 0;
  899.         while (MasterPointerScan != NIL)
  900.             {
  901.                 IterateCount += 1;
  902.                 if ((MasterPointerScan < LowestValidAddress)
  903.                     || (MasterPointerScan >= HighestValidAddress)
  904.                     || (((long)MasterPointerScan & 0x03) != 0))
  905.                     {
  906.                         DebugStr("\pCorrupt Master Pointer List");
  907.                         return;
  908.                     }
  909.                 if (IterateCount > MAXITERATION)
  910.                     {
  911.                         DebugStr("\pHeap check iteration limit exceeded");
  912.                         return;
  913.                     }
  914.                 MasterPointerScan = (char*)*(long*)MasterPointerScan;
  915.             }
  916.     }
  917.  
  918.  
  919. void            SetTopOfStack(char* ATopVar)
  920.     {
  921.         TopOfStack = ATopVar;
  922.     }
  923.  
  924. #pragma options(!profile)
  925.  
  926. void            StackSizeTest(void)
  927.     {
  928.         char            AStupidVariable;
  929.  
  930.         if ((long)(TopOfStack - &AStupidVariable) > MaximumStackSize)
  931.             {
  932.                 MaximumStackSize = (TopOfStack - &AStupidVariable);
  933.             }
  934. //    if (MaximumStackSize >= STACKSIZE - 256)
  935. //        {
  936. //            DebugStr("\pStack overflow");
  937. //        }
  938.     }
  939.  
  940.  
  941. #endif /* } */
  942.